package be.kuleuven.cs.mop.app.controllers;


import static junit.framework.Assert.*;

import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;

import org.junit.*;

import be.kuleuven.cs.mop.TestEnvironment;
import be.kuleuven.cs.mop.app.controllers.UserController;
import be.kuleuven.cs.mop.domain.exceptions.InvalidCurrentUserException;
import be.kuleuven.cs.mop.domain.exceptions.TaskManagerException;
import be.kuleuven.cs.mop.domain.model.Invitation;
import be.kuleuven.cs.mop.domain.model.Task;
import be.kuleuven.cs.mop.domain.model.TaskType;
import be.kuleuven.cs.mop.domain.model.User;
import be.kuleuven.cs.mop.domain.model.impl.Field;
import be.kuleuven.cs.mop.domain.model.impl.FieldType;
import be.kuleuven.cs.mop.domain.model.impl.Interval;
import be.kuleuven.cs.mop.domain.model.impl.ResourceTypeImpl;
import be.kuleuven.cs.mop.domain.model.impl.Schedule;
import be.kuleuven.cs.mop.domain.model.impl.TaskTypeImpl;
import be.kuleuven.cs.mop.domain.model.impl.UserTypeImpl;



public class UserControllerTest {
	
	private static TestEnvironment ENV;
	
	private static UserController ctrl;
	
	
	
	@Before
	public void setUp() throws Exception {
		ENV = TestEnvironment.newInstance();
		
		ctrl = ENV.controllers.getControllerUsers();
		ctrl.setUser(ENV.admin);
	}
	
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {}
	
	@After
	public void tearDown() throws Exception {}
	
	@AfterClass
	public static void tearDownAfterClass() throws Exception {}
	
	
	
	@Test
	public void testAddUserInvitation()
			throws InvalidCurrentUserException, TaskManagerException {
		final HashMap<UserTypeImpl, Interval> constraints =
			new HashMap<UserTypeImpl, Interval>();
		constraints.put(ENV.userTypes.get(1), new Interval(1, 1));
		final TaskType type = new TaskTypeImpl(
				ENV.world, "TempTaskType",
				new HashSet<UserTypeImpl>(ENV.world.getUserTypes()),
				constraints,
				new HashMap<String, FieldType>(),
				new HashMap<ResourceTypeImpl, Interval>());
		final Task task = ENV.controllers.getControllerTasks().createTask(
				ENV.schedule1,
				null,
				new HashMap<String, Field>(),
				type);
		
		assertTrue(ctrl.getInvitations(task).isEmpty());
		ctrl.addUserInvitation(task, ENV.user2);
		for (final Invitation invitation : ctrl.getInvitations(task))
			if (invitation.getUser().equals(ENV.user2))
				return;
		assertFalse(true);	//	Invitation was not added
	}
	
	public void testAdjustClockValueWithAdmin() {
		try {
			ENV.system.setUser(ENV.admin);
		} catch (TaskManagerException e1) {
			assertFalse(true);
		}
		
		try {
			ctrl.adjustClockValue(ENV.datum1);
		} catch (final InvalidCurrentUserException e) {
			assertFalse(true);
		}
		
		assertEquals(ENV.system.getWorld().getClock().getTime(), ENV.datum1);
	}
	
	public void testAdjustClockValueWithUser() {
		final Calendar originalTime = ENV.system.getWorld().getClock().getTime();
		
		try {
			ENV.system.setUser(ENV.user1);
		} catch (TaskManagerException e1) {
			assertFalse(true);
		}
		
		try {
			ctrl.adjustClockValue(ENV.datum1);
			assertFalse(true);	//	should not be reached
		} catch (final InvalidCurrentUserException e) {
			//	must be reached
		}
		
		assertEquals(ENV.system.getWorld().getClock().getTime(), originalTime);
	}
	
	@Test(expected=TaskManagerException.class)
	public void testCreateUserInvalidClone()
			throws InvalidCurrentUserException, TaskManagerException {
		ctrl.createUser("name", ENV.userTypes.get(0));
		ctrl.createUser("name", ENV.userTypes.get(0));
	}
	
	@Test(expected=TaskManagerException.class)
	public void testCreateUserInvalidEmpty()
			throws InvalidCurrentUserException, TaskManagerException {
		ctrl.createUser("", ENV.userTypes.get(0));
	}
	
	@Test(expected=TaskManagerException.class)
	public void testCreateUserInvalidNull()
			throws InvalidCurrentUserException, TaskManagerException {
		ctrl.createUser(null, ENV.userTypes.get(0));
	}
	
	@Test
	public void testCreateUserValid()
			throws InvalidCurrentUserException, TaskManagerException {
		final User user = ctrl.createUser("RandomUser", ENV.userTypes.get(1));
		assertNotNull(user);
		assertTrue(ENV.world.getUsers().contains(user));
	}
	
	@Test
	public void testRemoveUserInvitation()
			throws InvalidCurrentUserException, TaskManagerException {
		final HashMap<UserTypeImpl, Interval> constraints =
			new HashMap<UserTypeImpl, Interval>();
		constraints.put(ENV.userTypes.get(1), new Interval(1, 1));
		final TaskType type = new TaskTypeImpl(
				ENV.world, "TempTaskType",
				new HashSet<UserTypeImpl>(ENV.world.getUserTypes()),
				constraints,
				new HashMap<String, FieldType>(),
				new HashMap<ResourceTypeImpl, Interval>());
		final Task task = ENV.controllers.getControllerTasks().createTask(
				ENV.schedule1,
				null,
				new HashMap<String, Field>(),
				type);
		
		assertTrue(ctrl.getInvitations(task).isEmpty());
		ctrl.addUserInvitation(task, ENV.user2);


		Invitation invitation = null;
		for (final Invitation inv : ctrl.getInvitations(task)) {
			if (inv.getUser().equals(ENV.user2)) {
				invitation = inv;
				break;
			}
		}
		assertNotNull(invitation);
		
		ctrl.removeUserInvitation(invitation);
		assertTrue(ctrl.getInvitations(task).isEmpty());
	}
	
	@Test(expected=TaskManagerException.class)
	public void testSetUserInvalid() throws TaskManagerException {
		ctrl.setUser(null);
	}
	
	@Test
	public void testSetUserValid()
			throws InvalidCurrentUserException, TaskManagerException  {
		final User user = ctrl.createUser("VALID", ENV.userTypes.get(0));
		assertNotNull(user);
		ctrl.setUser(user);	// waarom zaagt hij hier niet ??
		
		final Task task = ENV.controllers.getControllerTasks().createTask(
				new Schedule(ENV.datum1, ENV.datum2, ENV.duration),
				null,
				new HashMap<String, Field>(),
				ENV.testTaskType);
		
		assertNotNull(task);
		assertTrue(task.getUser().getName().equals("VALID"));	// enkel om te testen over user bestaat met die naam ??
	}
	
	@Test
	public void testGetCurrentLoggedInUserInValid()
			throws InvalidCurrentUserException, TaskManagerException {
		assertNotNull(ctrl.getCurrentLoggedInUser());
	}
	
	public void testGetCurrentLoggedInUserValid()
			throws InvalidCurrentUserException, TaskManagerException {
		final User user = ctrl.createUser("VALID", ENV.userTypes.get(0));
		assertNotNull(user);
		ctrl.setUser(user);
		assertEquals(user,ctrl.getCurrentLoggedInUser());
	}
	
}